package design.donkey.auto.ddl.dialect.mysql.handler;

import design.donkey.auto.ddl.model.ColumnMetaModel;

/**
 * 列类型处理
 * 
 * @since 0.0.1
 * @author zhangjiakung
 */
public class ColumnHandlerForJdbcType implements ColumnHandler {

    @Override
    public String handle(ColumnMetaModel columnMetaModel) {
        return switch (columnMetaModel.getJdbcType()) {
            // 整数
            case TINYINT -> intTypeHandler(columnMetaModel, 3);
            case SMALLINT -> intTypeHandler(columnMetaModel, 5);
            case MEDIUMINT -> intTypeHandler(columnMetaModel, 8);
            case INT -> intTypeHandler(columnMetaModel, 10);
            case BIGINT -> intTypeHandler(columnMetaModel, 20);
            // 浮点数
            case DECIMAL -> decimalTypeHandler(columnMetaModel);
            // 字符串
            case CHAR -> lengthTypeHandler(columnMetaModel, 255, 255);
            case VARCHAR -> lengthTypeHandler(columnMetaModel, 255, 65535);
            // 有长度二进制
            case BIT -> lengthTypeHandler(columnMetaModel, 1, 64);
            case BINARY -> lengthTypeHandler(columnMetaModel, 1, 255);
            case VARBINARY -> lengthTypeHandler(columnMetaModel, 1, 65535);
            // 文本
            // 二进制
            // 时间
            // json
            case TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB, TIME, DATE, DATETIME, TIMESTAMP, JSON -> noLengthHandler(
                columnMetaModel);
            default -> noLengthHandler(columnMetaModel);
        };
    }

    /**
     * 没有长度的类型处理 <br/>
     *
     *
     * @param columnMetaModel 模型字段
     * @return 处理后的类型
     */
    private String noLengthHandler(ColumnMetaModel columnMetaModel) {
        return columnMetaModel.getJdbcType().name().toLowerCase();
    }

    /**
     * 字符串类型处理
     *
     * @param columnMetaModel 列信息
     * @param maxZerofillLength 最大 0 填充长度
     * @return 处理后的类型
     */
    private String intTypeHandler(ColumnMetaModel columnMetaModel, int maxZerofillLength) {
        boolean zerofill = columnMetaModel.isZerofill();
        if (zerofill) {
            int zerofillLength = lengthHandler(columnMetaModel.getLength(), maxZerofillLength, maxZerofillLength);
            if (zerofillLength == 0) {
                return columnMetaModel.getJdbcType().name().toLowerCase();
            }
            // 填充0
            return String.format("%s(%d)", columnMetaModel.getJdbcType().name().toLowerCase(), zerofillLength);
        } else {
            // 不填充0
            return columnMetaModel.getJdbcType().name().toLowerCase();
        }

    }

    /**
     * 浮点数类型处理
     * 
     * @param columnMetaModel 模型字段
     * @return 处理后的类型
     */
    private String decimalTypeHandler(ColumnMetaModel columnMetaModel) {
        int precision = lengthHandler(columnMetaModel.getPrecision(), 10, 65);
        int scale = lengthHandler(columnMetaModel.getScale(), 0, 30);
        return String.format("%s(%d,%d)", columnMetaModel.getJdbcType().name().toLowerCase(), precision, scale);
    }

    /**
     * 可变二进制类型处理
     *
     * @param columnMetaModel 模型字段
     * @param defaultLength 默认长度
     * @param maxLength 最大长度
     * @return 处理后的类型
     */
    private String lengthTypeHandler(ColumnMetaModel columnMetaModel, int defaultLength, int maxLength) {
        // 获取字符长度
        int length = lengthHandler(columnMetaModel.getLength(), defaultLength, maxLength);
        return String.format("%s(%d)", columnMetaModel.getJdbcType().name().toLowerCase(), length);
    }

    /**
     * value 值处理 0 <= value <= maxValue; <br/>
     *
     *
     * 当 value 小于 0 或为 null 时 返回 defaultValue <br/>
     *
     * 当 value 大于 maxValue 时 返回 maxValue <br/>
     *
     * 其余情况 返回 value
     *
     * @param value 待处理值
     * @param defaultValue 默认值
     * @param maxValue 最大值
     * @return 处理后的值
     */
    private int lengthHandler(Integer value, int defaultValue, int maxValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value < 0) {
            return defaultValue;
        }
        if (value > maxValue) {
            return maxValue;
        }
        return value;
    }
}
